package tfsIssueTracker.commands;

import com.intellij.execution.configurations.GeneralCommandLine;
import jetbrains.buildServer.ExecResult;
import jetbrains.buildServer.util.StringUtil;
import jetbrains.buildServer.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import tfsIssueTracker.CommandUtil;
import tfsIssueTracker.Settings;

import java.util.Collections;
import java.util.Set;

public abstract class TfsCommand<TResult> {
    private Settings mySettings;

    public TfsCommand(@NotNull final Settings settings) {
        mySettings = settings;
    }

    protected GeneralCommandLine createCommandLine() {
        GeneralCommandLine cli = new GeneralCommandLine();
        cli.setExePath(mySettings.getWrapper().getAbsolutePath());
        cli.setPassParentEnvs(true);

        cli.addParameter("/mode:client");
        cli.addParameter("/server:" + mySettings.getHost());

        if (mySettings.getUsername() != null) {
            cli.addParameter("/user:" + mySettings.getUsername());
        }

        if (mySettings.getPassword() != null) {
            cli.addParameter("/password:" + mySettings.getPassword());
        }

        cli.addParameter("/command:" + getCommandName());

        addCommandSpecificArguments(cli);

        return cli;
    }

    protected void addCommandSpecificArguments(GeneralCommandLine cli) {
    }

    protected abstract String getCommandName();

    protected ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException {
        return CommandUtil.runCommand(cli, getPrivateData());
    }

    protected ExecResult runCommand(@NotNull GeneralCommandLine cli, int executionTimeout) throws VcsException {
        return CommandUtil.runCommand(cli, executionTimeout, getPrivateData());
    }

    protected void failIfNotEmptyStdErr(@NotNull GeneralCommandLine cli, @NotNull ExecResult res) throws VcsException {
        if (!StringUtil.isEmpty(res.getStderr())) {
            CommandUtil.commandFailed(cli.getCommandLineString(), res);
        }
    }

    protected void failIfNonZeroExitCode(@NotNull GeneralCommandLine cli, @NotNull ExecResult res) throws VcsException {
        if (res.getExitCode() != 0) {
            CommandUtil.commandFailed(cli.getCommandLineString(), res);
        }
    }

    public Set<String> getPrivateData() {
        return Collections.singleton(mySettings.getPassword());
    }

    public TResult execute() throws VcsException {
        GeneralCommandLine cli = createCommandLine();

        ExecResult result = runCommand(cli);

        if (shouldFailIfNonZeroExitCode()) {
            failIfNonZeroExitCode(cli, result);
        }

        if (shouldFailIfNotEmptyStdErr()) {
            failIfNotEmptyStdErr(cli, result);
        }

        return parseResult(result.getStdout());
    }

    protected abstract TResult parseResult(String stdout);

    protected boolean shouldFailIfNotEmptyStdErr() {
        return true;
    }

    protected boolean shouldFailIfNonZeroExitCode() {
        return true;
    }
}